#include "sdk_port.h"
#include "netinet/in.h"
#include "sdk.h"
#include <arpa/inet.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <net/if.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>

char *netcardName = "enp0s8";

int sdk_port_random_get(void) {
  static int random = 0x1234;

  random += 1;
  unsigned long nowustime = 0;
  struct timeval nowtime;
  gettimeofday(&nowtime, NULL);
  nowustime = nowtime.tv_sec;
  nowustime = nowustime * 1000000 + nowtime.tv_usec;

  return nowustime & 0xFFFFFFFF;
}

//========================socket=============================

int sdk_port_udp_socket_create(int *fd, unsigned short port) {
  int ret = -1;
  struct sockaddr_in addr;
  if (fd == NULL) {
    printf("%s null pointer.", __FUNCTION__);
    return ret;
  }

  // socket create
  *fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (*fd == -1) {
    printf("%s:socket create error.", __FUNCTION__);
    return ret;
  }
  // set addr
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(port);

  // bind
  if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
    printf("%s: bind error.", __FUNCTION__);
    goto _out;
  }

  return 0;

_out:
  if (*fd) {
    close(*fd);
    *fd = -1;
  }

  return ret;
}

int sdk_port_udp_socket_close(int *sockfd) {
  close(*sockfd);
  *sockfd = -1;
  return 0;
}

int sdk_port_socket_sendto(int fd, const void *buf, long unsigned int len,
                           int flags, const struct sockaddr *target_addr,
                           unsigned int target_len) {
  int ret = sendto(fd, buf, len, flags, target_addr, target_len);
  if (ret > 0)
    return len;

  return -1;
}

int sdk_port_socket_recvform(int fd, void *buf, long unsigned int len,
                             int flags, struct sockaddr *source_addr,
                             unsigned int *source_len) {
  return recvfrom(fd, buf, len, flags, source_addr, source_len);
}

unsigned int sdk_port_htonl(unsigned int hostlong) { return htonl(hostlong); }

unsigned short sdk_port_htons(unsigned short n) { return htons(n); }

unsigned short sdk_port_ntohs(unsigned short n) { return ntohs(n); }

unsigned int sdk_port_inet_addr(const char *cp) { return inet_addr(cp); }

int sdk_port_get_mac_addr(unsigned char *mac_addr) {
  struct ifreq ifr;
  struct ifconf ifc;
  char buf[1024] = {0};
  // int success = 0;
  int ret = -1;

  int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  if (sock == -1) {
    printf("%s: socket error.", __FUNCTION__);
    return -1;
  }

  ifc.ifc_len = sizeof(buf);
  ifc.ifc_buf = buf;
  if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
    printf("%s: ioctl error.", __FUNCTION__);
    goto END;
    ;
  }

  struct ifreq *it = ifc.ifc_req;
  const struct ifreq *const end = it + (ifc.ifc_len / sizeof(struct ifreq));
  char szMac[64];
  int count = 0;
  for (; it != end; ++it) {
    strcpy(ifr.ifr_name, it->ifr_name);
    if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
      if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
        if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
          count++;
          unsigned char *ptr;
          ptr = (unsigned char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];
          snprintf(szMac, 64, "%02X:%02X:%02X:%02X:%02X:%02X", *ptr, *(ptr + 1),
                   *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5));

          if (strcmp(ifr.ifr_name, netcardName) == 0) {
            memcpy(mac_addr, ptr, 6);
            ret = 0;
            goto END;
          }
        }
      }
    } else {
      printf("get mac info error");
      goto END;
    }
  }

END:
  close(sock);
  return ret;
}

int sdk_port_get_ip(char *ipstr) {
  int inet_sock = -1;
  struct ifreq ifr;
  inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
  strcpy(ifr.ifr_name, netcardName);

  if (ioctl(inet_sock, SIOCGIFADDR, &ifr) < 0) {
    perror("ioctl");
    return SDK_SOCKIOCTL_ERR;
  }
  char *ip = inet_ntoa(((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr);
  strcpy(ipstr, ip);
  return inet_addr(ipstr);
}

/*
int sdk_port_tcp_socket_create(int * fd,unsigned short port)
{

    int ret = -1;
    struct sockaddr_in addr;
    if(fd==NULL){
        //ya_printf(C_LOG_ERROR,"%s: null pointer.\r\n",__FUNCTION__);
        sdk_printf("%s: null pointer.",__FUNCTION__);
        return ret;
    }

    //socket create
    *fd =  socket(AF_INET,SOCK_STREAM,0);
    if(*fd == -1){
        //ya_printf(C_LOG_ERROR,"%s:socket create error.\r\n",__FUNCTION__);
        sdk_printf("%s:socket create error.",__FUNCTION__);
        return ret;
    }
    //set addr
    memset(&addr,0,sizeof(addr));
    addr.sin_family  =  AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);

    //bind
    if(bind(*fd,(struct sockaddr*)&addr,sizeof(addr)) != 0){
        //ya_printf(C_LOG_ERROR,"%s: bind error.\r\n",__FUNCTION__);
        sdk_printf("%s: bind error.",__FUNCTION__);
        goto _out;
    }

    //listen
    if(listen(*fd,5)!=0){
        //ya_printf(C_LOG_ERROR,"%s: listen error.\r\n",__FUNCTION__);
        sdk_printf("%s: listen error.",__FUNCTION__);
        goto _out;
    }

    return 0;

_out:
    if(*fd){
        close(*fd);
        *fd = -1;
    }


    return ret;
}
*/

int sdk_port_thread_create(sdk_port_thread_t *thandle, const char *name,
                           void *(*main_func)(void *arg), void *arg,
                           int stack_depth, int priority) {

  if (pthread_create(thandle, NULL, main_func, arg))
    return -1;

  return 0;
}

int sdk_port_thread_delete(sdk_port_thread_t *thandle) {
  pthread_cancel(*thandle);
  return 0;
}

void sdk_port_thread_sleep(int mses) {
  usleep(mses * 1000);
  return;
}

void sdk_port_thread_suspend(sdk_port_thread_t *thandle) { return; }

void sdk_port_thread_resume(sdk_port_thread_t *thandle) { return; }

int sdk_port_printf(const char *fmt, ...) {
  va_list args;
  va_start(args, fmt);
  vprintf(fmt, args);
  va_end(args);
  return 0;
}
